package com.douya.pangu.application.sys.service;

import com.douya.common.intercetor.HttpLoggingService;
import com.douya.common.utils.IPUtils;
import com.douya.common.utils.JsonUtils;
import com.douya.pangu.business.api.pojo.dto.BusinessHttpLogDTO;
import com.douya.pangu.core.api.sys.fegin.UserDetailsImpl;
import com.douya.security.utils.SecurityUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;
import org.springframework.web.util.WebUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;

/**
 * @Author hcy
 * @Date 2024/3/22  10:40
 */
@Service
@Slf4j
public class HttpLog implements HttpLoggingService {

    @Value("${spring.application.name}")
    String applicationName;

    @Resource
    BusinessHttpLogService businessHttpLogService;

    /**
     * 记录日志
     *
     * @param request  请求
     * @param response 响应
     * @param handler  处理器
     */
    @Override
    public void saveLog(HttpServletRequest request, HttpServletResponse response, Object handler) {
        String path = request.getRequestURI().replaceFirst(request.getContextPath(), "");
        if (!isRequestValid(request)) {
            return;
        }
        if (!(request instanceof ContentCachingRequestWrapper)) {
            request = new ContentCachingRequestWrapper(request);
        }
        if (!(response instanceof ContentCachingResponseWrapper)) {
            response = new ContentCachingResponseWrapper(response);
        }
        int status = response.getStatus();
        long startTime = request.getAttribute(applicationName + "beginTime") == null ?
                0L : (long) request.getAttribute(applicationName + "beginTime");
        UserDetailsImpl userDetails = SecurityUtils.getCurrentUserDetail(UserDetailsImpl.class);
        LocalDateTime dateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(startTime), ZoneId.systemDefault());
        String parameterMap = JsonUtils.toJson(request.getParameterMap());
        BusinessHttpLogDTO businessHttpLogDTO = new BusinessHttpLogDTO();
        businessHttpLogDTO.setUserId(userDetails == null ? null : Long.valueOf(userDetails.getId()))
                .setPath(path)
                .setMethod(request.getMethod())
                .setIpAddr(IPUtils.getIpAddr(request))
                .setTimeTaken((int) (System.currentTimeMillis() - startTime))
                .setRequestTime(dateTime)
                .setParameterMap(parameterMap == null || parameterMap.length() > 1000 ? null : parameterMap)
                .setStatus(status)
                .setRequestBody(getRequestBody(request))
                .setResponseBody(getResponseBody(response));
        businessHttpLogService.insert(businessHttpLogDTO);
    }

    private boolean isRequestValid(HttpServletRequest request) {
        try {
            new URI(request.getRequestURL().toString());
            return true;
        } catch (URISyntaxException ex) {
            return false;
        }
    }

    private String getRequestBody(HttpServletRequest request) {
        String requestBody = "";
        ContentCachingRequestWrapper wrapper = WebUtils.getNativeRequest(request, ContentCachingRequestWrapper.class);
        if (wrapper != null) {
            try {
                requestBody = IOUtils.toString(wrapper.getContentAsByteArray(), wrapper.getCharacterEncoding());
            } catch (IOException e) {
                // NOOP
            }
        }
        return requestBody.length() > 1000 ? null : requestBody;
    }

    private String getResponseBody(HttpServletResponse response) {
        String responseBody = "";
        ContentCachingResponseWrapper wrapper = WebUtils.getNativeResponse(response, ContentCachingResponseWrapper.class);
        if (wrapper != null) {
            try {
                responseBody = IOUtils.toString(wrapper.getContentAsByteArray(), wrapper.getCharacterEncoding());
            } catch (IOException e) {
                // NOOP
            }
        }
        return responseBody.length() > 300 ? null : responseBody;
    }
}
